﻿using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Imaging;
using System.Linq;
using System.Text;

namespace MyWatermark
{

    //另一种方式
    class DwtTextWatermarkingTest3
    {
        // 执行1D离散小波变换
        private static double[] PerformDwt1D(double[] data)
        {
            int n = data.Length;
            double[] result = new double[n];
            for (int i = 0; i < n / 2; i++)
            {
                result[i] = (data[2 * i] + data[2 * i + 1]) / Math.Sqrt(2);
                result[i + n / 2] = (data[2 * i] - data[2 * i + 1]) / Math.Sqrt(2);
            }
            return result;
        }

        // 执行1D逆离散小波变换
        private static double[] PerformInverseDwt1D(double[] data)
        {
            int n = data.Length;
            double[] result = new double[n];
            for (int i = 0; i < n / 2; i++)
            {
                result[2 * i] = (data[i] + data[i + n / 2]) / Math.Sqrt(2);
                result[2 * i + 1] = (data[i] - data[i + n / 2]) / Math.Sqrt(2);
            }
            return result;
        }

        // 对2D数组执行DWT（先在行上，再在列上）
        // 修改后的2D DWT支持多级分解
        private static double[,] PerformDwt2D(double[,] image, int levels = 2)
        {
            int rows = image.GetLength(0);
            int cols = image.GetLength(1);
            double[,] result = (double[,])image.Clone();

            for (int level = 0; level < levels; level++)
            {
                int currentRows = rows >> level;
                int currentCols = cols >> level;

                // 行变换
                for (int i = 0; i < currentRows; i++)
                {
                    double[] row = Enumerable.Range(0, currentCols)
                                      .Select(j => result[i, j]).ToArray();
                    double[] dwtRow = PerformDwt1D(row);
                    for (int j = 0; j < currentCols; j++)
                        result[i, j] = dwtRow[j];
                }

                // 列变换
                for (int j = 0; j < currentCols; j++)
                {
                    double[] col = Enumerable.Range(0, currentRows)
                                      .Select(i => result[i, j]).ToArray();
                    double[] dwtCol = PerformDwt1D(col);
                    for (int i = 0; i < currentRows; i++)
                        result[i, j] = dwtCol[i];
                }
            }
            return result;
        }

        private static double[,] PerformInverseDwt2D(double[,] transformedImage, int levels = 2)
        {
            int rows = transformedImage.GetLength(0);
            int cols = transformedImage.GetLength(1);
            double[,] result = (double[,])transformedImage.Clone();

            // 按反向层次逐步重构（从最深层次到第1层）
            for (int level = levels - 1; level >= 0; level--)
            {
                int currentSize = rows >> level;  // 当前重构区域尺寸
                int subbandSize = currentSize / 2;

                // 列逆变换（处理当前层次的所有列）
                for (int j = 0; j < currentSize; j++)
                {
                    double[] column = new double[currentSize];
                    for (int i = 0; i < currentSize; i++)
                    {
                        column[i] = result[i, j];
                    }
                    double[] idwtCol = PerformInverseDwt1D(column);
                    for (int i = 0; i < currentSize; i++)
                    {
                        result[i, j] = idwtCol[i];
                    }
                }

                // 行逆变换（处理当前层次的所有行）
                for (int i = 0; i < currentSize; i++)
                {
                    double[] row = new double[currentSize];
                    for (int j = 0; j < currentSize; j++)
                    {
                        row[j] = result[i, j];
                    }
                    double[] idwtRow = PerformInverseDwt1D(row);
                    for (int j = 0; j < currentSize; j++)
                    {
                        result[i, j] = idwtRow[j];
                    }
                }

                // 重组子带数据（仅当不是最后一级时需要）
                if (level > 0)
                {
                    double[,] temp = new double[currentSize, currentSize];
                    int parentSize = currentSize * 2;

                    // 将低频子带（左上角）复制到临时缓冲区
                    for (int i = 0; i < subbandSize; i++)
                    {
                        for (int j = 0; j < subbandSize; j++)
                        {
                            temp[i, j] = result[i, j];
                        }
                    }

                    // 重组四象限到父级空间
                    for (int i = 0; i < subbandSize; i++)
                    {
                        for (int j = 0; j < subbandSize; j++)
                        {
                            // 低频LL（左上）
                            result[i, j] = temp[i, j];
                            // 水平细节HL（右上）
                            result[i, j + subbandSize] = result[i, j + subbandSize];
                            // 垂直细节LH（左下）
                            result[i + subbandSize, j] = result[i + subbandSize, j];
                            // 对角细节HH（右下）
                            result[i + subbandSize, j + subbandSize] = result[i + subbandSize, j + subbandSize];
                        }
                    }
                }
            }

            return result;
        }

        // 将文本转换为二进制序列
        private static List<bool> TextToBinaryWithHeader(string text)
        {
            byte[] bytes = Encoding.UTF8.GetBytes(text);
            List<bool> binaryList = new List<bool>();

            // 添加4字节（32位）长度头
            byte[] lengthHeader = BitConverter.GetBytes(bytes.Length);
            foreach (byte b in lengthHeader)
            {
                binaryList.AddRange(Convert.ToString(b, 2).PadLeft(8, '0').Select(c => c == '1'));
            }

            // 添加文本数据
            foreach (byte b in bytes)
            {
                binaryList.AddRange(Convert.ToString(b, 2).PadLeft(8, '0').Select(c => c == '1'));
            }
            return binaryList;
        }

        // 提取时读取长度头
        private static string BinaryToTextWithHeader(List<bool> binaryList)
        {
            // 读取前32位（4字节）长度头
            byte[] lengthBytes = new byte[4];
            for (int i = 0; i < 32; i += 8)
            {
                string byteStr = string.Join("", binaryList.GetRange(i, 8).Select(b => b ? "1" : "0"));
                lengthBytes[i / 8] = Convert.ToByte(byteStr, 2);
            }
            int length = BitConverter.ToInt32(lengthBytes, 0);

            // 读取后续数据
            List<byte> dataBytes = new List<byte>();
            for (int i = 32; i < 32 + length * 8; i += 8)
            {
                string byteStr = string.Join("", binaryList.GetRange(i, 8).Select(b => b ? "1" : "0"));
                dataBytes.Add(Convert.ToByte(byteStr, 2));
            }
            return Encoding.UTF8.GetString(dataBytes.ToArray());
        }

        // 计算局部方差
        private static double CalculateLocalVariance(double[,] image, int x, int y, int blockSize = 3)
        {
            double sum = 0, sumSq = 0;
            int count = 0;
            for (int i = x - blockSize / 2; i <= x + blockSize / 2; i++)
            {
                for (int j = y - blockSize / 2; j <= y + blockSize / 2; j++)
                {
                    if (i >= 0 && i < image.GetLength(0) && j >= 0 && j < image.GetLength(1))
                    {
                        double val = image[i, j];
                        sum += val;
                        sumSq += val * val;
                        count++;
                    }
                }
            }
            double mean = sum / count;
            return sumSq / count - mean * mean;
        }

        // 嵌入文本水印
        public static Bitmap EmbedTextWatermark(Bitmap hostImage, string watermarkText)
        {
            List<bool> binaryWatermark = TextToBinaryWithHeader(watermarkText);

            double[,] imageData = new double[hostImage.Height, hostImage.Width];
            for (int i = 0; i < hostImage.Height; i++)
            {
                for (int j = 0; j < hostImage.Width; j++)
                {
                    Color pixel = hostImage.GetPixel(j, i);
                    imageData[i, j] = pixel.GetBrightness();
                }
            }

            double[,] dwtImage = PerformDwt2D(imageData);

            int watermarkIndex = 0;
            //for (int i = 0; i < dwtImage.GetLength(0); i++)
            //{
            //    for (int j = 0; j < dwtImage.GetLength(1); j++)
            //    {
            //        if (watermarkIndex < binaryWatermark.Count)
            //        {
            //            if (binaryWatermark[watermarkIndex])
            //            {
            //                dwtImage[i, j] += alpha;
            //            }
            //            else
            //            {
            //                dwtImage[i, j] -= alpha;
            //            }
            //            watermarkIndex++;
            //        }
            //        else
            //        {
            //            break;
            //        }
            //    }
            //    if (watermarkIndex >= binaryWatermark.Count)
            //    {
            //        break;
            //    }
            //}


            //int ll2Size = hostImage.Height / 4;
            //for (int i = 0; i < ll2Size; i++)
            //{
            //    for (int j = 0; j < ll2Size; j++)
            //    {

            //        double baseAlpha = 0.1;
            //        double localVar = CalculateLocalVariance(dwtImage, i, j);
            //        double adaptiveAlpha = baseAlpha * (1 + Math.Log(1 + localVar)); // 对数调整


            //        // 在LL2子带嵌入水印
            //        if (watermarkIndex < binaryWatermark.Count)
            //        {
            //            //dwtImage[i, j] += binaryWatermark[watermarkIndex] ? alpha : -alpha;
            //            dwtImage[i, j] += binaryWatermark[watermarkIndex] ? adaptiveAlpha : -adaptiveAlpha;

            //            watermarkIndex++;
            //        }
            //    }
            //}

            // 修改EmbedTextWatermark中的嵌入逻辑，仅修改HL/LH子带
            int subbandStart = hostImage.Height / 2; // 选择HL子带
            for (int i = subbandStart; i < dwtImage.GetLength(0); i++)
            {
                for (int j = 0; j < subbandStart; j++)
                {
                    double baseAlpha = 0.1;
                    double localVar = CalculateLocalVariance(dwtImage, i, j);
                    double adaptiveAlpha = baseAlpha * (1 + Math.Log(1 + localVar)); // 对数调整

                    // 在HL子带（右侧上半部）嵌入
                    if (watermarkIndex < binaryWatermark.Count)
                    {
                        dwtImage[i, j] += binaryWatermark[watermarkIndex] ? adaptiveAlpha : -adaptiveAlpha;
                        watermarkIndex++;
                    }
                }
            }

            double[,] inverseDwtImage = PerformInverseDwt2D(dwtImage);

            Bitmap watermarkedBitmap = new Bitmap(hostImage.Width, hostImage.Height);
            for (int i = 0; i < hostImage.Height; i++)
            {
                for (int j = 0; j < hostImage.Width; j++)
                {
                    double brightness = inverseDwtImage[i, j];
                    brightness = Math.Max(0, Math.Min(1, brightness));
                    Color originalColor = hostImage.GetPixel(j, i);
                    //Color newColor = Color.FromArgb(originalColor.A,
                    //    (int)(brightness * 255), (int)(brightness * 255), (int)(brightness * 255));

                    // 改为仅修改蓝色通道：
                    Color newColor = Color.FromArgb(
                        originalColor.A,
                        originalColor.R,  // 保留红色
                        originalColor.G,  // 保留绿色
                        (int)(brightness * 255)  // 仅修改蓝色
                    );



                    watermarkedBitmap.SetPixel(j, i, newColor);
                }
            }

            return watermarkedBitmap;
        }

        // 提取文本水印
        public static string ExtractTextWatermark(Bitmap watermarkedImage, Bitmap originalImage, int watermarkLength)
        {
            double[,] watermarkedData = new double[watermarkedImage.Height, watermarkedImage.Width];
            double[,] originalData = new double[originalImage.Height, originalImage.Width];

            for (int i = 0; i < watermarkedImage.Height; i++)
            {
                for (int j = 0; j < watermarkedImage.Width; j++)
                {
                    Color pixel = watermarkedImage.GetPixel(j, i);
                    watermarkedData[i, j] = pixel.GetBrightness();
                }
            }

            for (int i = 0; i < originalImage.Height; i++)
            {
                for (int j = 0; j < originalImage.Width; j++)
                {
                    Color pixel = originalImage.GetPixel(j, i);
                    originalData[i, j] = pixel.GetBrightness();
                }
            }

            double[,] watermarkedDwt = PerformDwt2D(watermarkedData);
            double[,] originalDwt = PerformDwt2D(originalData);

            List<bool> extractedBinary = new List<bool>();
            for (int i = 0; i < watermarkedDwt.GetLength(0); i++)
            {
                for (int j = 0; j < watermarkedDwt.GetLength(1); j++)
                {
                    if (extractedBinary.Count < watermarkLength)
                    {
                        double diff = watermarkedDwt[i, j] - originalDwt[i, j];
                        extractedBinary.Add(diff > 0);
                    }
                    else
                    {
                        break;
                    }
                }
                if (extractedBinary.Count >= watermarkLength)
                {
                    break;
                }
            }

            return BinaryToTextWithHeader(extractedBinary);
        }

        public static void main()
        {
            string originalImagePath = @"D:\ywd\work\ncs\新水印的尝试\blind_watermark\blind_watermark\examples\pic\original.jpg";
            string watermarkedImagePath = @"D:\ywd\work\ncs\新水印的尝试\blind_watermark\blind_watermark\examples\pic\out1111111111111111.jpg";

            Bitmap originalBitmap = new Bitmap(originalImagePath);
            string watermarkText = "Hello, World!";
            double alpha = 0.01;

            // 嵌入水印
            Bitmap watermarkedBitmap = DwtTextWatermarking.EmbedTextWatermark(originalBitmap, watermarkText);
            watermarkedBitmap.Save(watermarkedImagePath, ImageFormat.Jpeg);

            // 提取水印
            Bitmap watermarkedFromFile = new Bitmap(watermarkedImagePath);
            string extractedText = DwtTextWatermarking.ExtractTextWatermark(watermarkedFromFile, originalBitmap);
            Console.WriteLine("提取的文本水印: " + extractedText);
        }

    }
}
